package org.setec.utils.xml;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class XMLLoader {

    protected static List getStringAttributes(Document document, String path, String attributeName) {
        List result = new ArrayList();
        String[] pathElements = path.split("\\|");
        List nodes = new ArrayList();
        lookup(nodes, document.getFirstChild(), pathElements, 0);
        for (Iterator it = nodes.iterator(); it.hasNext();) {
            Node node = (Node) it.next();
            Node attribute = node.getAttributes().getNamedItem(attributeName);
            if (attribute != null) {
                String attributeValue = attribute.getNodeValue();
                result.add(attributeValue);
            } else {
                System.out.println("Warning: XMLLoader - can't find attribute " + attributeName + " at path " + path);
            }
        }
        return result;
    }

    protected static String getStringAttribute(Document document, String path, String attributeName) {
        List attributes = getStringAttributes(document, path, attributeName);
        if (attributes.size() == 1) {
            return (String) attributes.get(0);
        } else {
            throw new IllegalStateException("Invalid number of attributes at:" + path + "@" + attributeName);
        }
    }

    protected static List getStringAttributes(Document document, String path, String attributeName, String filter) {
        List filterEntries = Arrays.asList(filter.split(";"));
        List filterList = new ArrayList();
        for (Iterator it = filterEntries.iterator(); it.hasNext();) {
            String filterEntry = (String) it.next();
            String filterPath = filterEntry.split("@")[0];
            String filterAttribute = filterEntry.split("@")[1].split("=")[0];
            String filterAttributeValue = filterEntry.split("@")[1].split("=")[1];
            filterList.add(new String[]{filterPath, filterAttribute, filterAttributeValue});
        }

        List result = new ArrayList();
        String[] pathElements = path.split("\\|");
        List nodes = new ArrayList();
        lookup(nodes, document.getFirstChild(), pathElements, 0, filterList);
        for (Iterator it = nodes.iterator(); it.hasNext();) {
            Node node = (Node) it.next();
            Node attribute = node.getAttributes().getNamedItem(attributeName);
            if (attribute != null) {
                String attributeValue = attribute.getNodeValue();
                result.add(attributeValue);
            } else {
                System.out.println("Warning: XMLLoader - can't find attribute " + attributeName + " at path " + path);
            }
        }
        return result;

    }

    protected static void lookup(List nodes, Node node, String[] pathElements, int pathCursor, List filterList) {

        if (pathCursor >= pathElements.length) {
            return;
        }
        if (node.getNodeName().equals(pathElements[pathCursor])) {

            boolean filterAttributeMatch = false;

            for (Iterator it = filterList.iterator(); it.hasNext();) {
                String[] filterDetails = (String[]) it.next();
                String[] filterPathElements = filterDetails[0].split("\\|");

                boolean filterPathMatch = true;
                for (int i = 0; i <= pathCursor && i < filterPathElements.length; i++) {
                    if (!pathElements[i].equals(filterPathElements[i])) {
                        filterPathMatch = false;
                    }
                }
                if (!filterPathMatch) {
                    continue;
                }

                if (filterPathElements.length == pathCursor + 1) {
                    Node attribute = node.getAttributes().getNamedItem(filterDetails[1]);
                    if (filterDetails[2].equals(attribute.getNodeValue())) {
                        filterAttributeMatch = true;
                    }
                } else {
                    filterAttributeMatch = true;
                }

            }

            if (!filterAttributeMatch) {
                return;
            }

            if (pathElements.length == pathCursor + 1) {
                nodes.add(node);
            } else {
                NodeList childNodes = node.getChildNodes();
                for (int nodeIndex = 0; nodeIndex < childNodes.getLength(); nodeIndex++) {
                    lookup(nodes, childNodes.item(nodeIndex), pathElements, pathCursor + 1, filterList);
                }
            }
        }
    }


    protected static void lookup(List nodes, Node node, String[] pathElements, int pathCursor) {
        if (pathCursor >= pathElements.length) {
            return;
        }
        if (node.getNodeName().equals(pathElements[pathCursor])) {
            if (pathElements.length == pathCursor + 1) {
                nodes.add(node);
            } else {
                NodeList childNodes = node.getChildNodes();
                for (int nodeIndex = 0; nodeIndex < childNodes.getLength(); nodeIndex++) {
                    lookup(nodes, childNodes.item(nodeIndex), pathElements, pathCursor + 1);
                }
            }
        }
    }

}
